package com.imooc.coupon.executor.impl;

import com.alibaba.fastjson.JSON;
import com.imooc.coupon.constant.CouponCategory;
import com.imooc.coupon.constant.RuleFlag;
import com.imooc.coupon.executor.AbstractExecutor;
import com.imooc.coupon.vo.CouponTemplateSDK;
import com.imooc.coupon.vo.GoodsInfo;
import com.imooc.coupon.vo.SettlementInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <h1>满减 + 折扣优惠券结算规则执行器</h1>
 * Created by Qinyi.
 */
@Slf4j
@Component
public class ManJianZheKouExecutor extends AbstractExecutor {

    /**
     * <h2>规则类型标记</h2>
     * @return {@link RuleFlag}
     */
    @Override
    public RuleFlag ruleConfig() {
        return RuleFlag.MANJIAN_ZHEKOU;
    }

    /**
     * <h2>校验商品类型与优惠券是否匹配</h2>
     * 需要注意:
     * 1. 这里实现的满减 + 折扣优惠券的校验
     * 2. 如果想要使用多类优惠券, 则必须要所有的商品类型都包含在内,
     * @param settlement {@link SettlementInfo} 用户传递的计算信息
     */
    @Override
    protected boolean isGoodTypeSatisfy(SettlementInfo settlement) {
        log.debug("Check ManJian And ZheKou Is Match Or Not!");
        // 结算商品列表
        List<Integer> goodsTypes = settlement.getGoodsInfos()
                .stream()
                .map(GoodsInfo::getType)
                .collect(Collectors.toList());
        // 优惠券商品类别
        List<Integer> couponGoodsTypes = new ArrayList<>();
        settlement.getCouponAndTemplateInfos().forEach(ct -> {
            couponGoodsTypes.addAll(
                    JSON.parseObject(ct.getTemplate().getRule().getUsage().getGoodsType(),List.class)
            );
        });

        // 如果想要使用多类优惠券, 则必须要所有的商品类型都包含在内
        return CollectionUtils.isSubCollection(goodsTypes,couponGoodsTypes);
    }

    /**
     * <h2>优惠券规则的计算</h2>
     * @param settlement {@link SettlementInfo} 包含了选择的优惠券
     * @return {@link SettlementInfo} 修正过的结算信息
     */
    @Override
    public SettlementInfo computeRule(SettlementInfo settlement) {
        // 商品总额
        double goodsSum = retain2Decimals(goodsCostSum(settlement.getGoodsInfos()));

        // 商品类型不匹配
        SettlementInfo notSatifySettlement = processGoodsTypeNotSatisfy(settlement, goodsSum);
        if(notSatifySettlement!=null){
            log.debug("ManJian Template Is Not Match To GoodsType!");
            return notSatifySettlement;
        }
        
        SettlementInfo.CouponAndTemplateInfo manJian = null;
        SettlementInfo.CouponAndTemplateInfo zheKou = null;
        for(SettlementInfo.CouponAndTemplateInfo ct : settlement.getCouponAndTemplateInfos() ){
            if(ct.getTemplate().getCategory().equals(CouponCategory.MANJIAN.getCode())){
                manJian = ct;
            }else if(ct.getTemplate().getCategory().equals(CouponCategory.ZHEKOU.getCode())){
                zheKou = ct;
            }
        }

        assert null != manJian;
        assert null != zheKou;

        // 当前的折扣优惠券和满减券如果不能共用(一起使用), 清空优惠券, 返回商品原价
        if (!isTemplateCanShared(manJian, zheKou)) {
            log.debug("Current ManJian And ZheKou Can Not Shared!");
            settlement.setCost(goodsSum);
            settlement.setCouponAndTemplateInfos(Collections.emptyList());
            return settlement;
        }

        // 最终的价格
        double targetSum = goodsSum;

        // 判断是否符合满减折扣标准
        double manjianBase = (double)manJian.getTemplate().getRule().getDiscount().getBase();   // 最低消费
        double manjianQuota = (double) manJian.getTemplate().getRule().getDiscount().getQuota();  // 折扣
        List<SettlementInfo.CouponAndTemplateInfo> ctInfos = new ArrayList<>();

        // 先计算满减
        if(targetSum >= manjianBase){
            targetSum -= manjianQuota;
            ctInfos.add(manJian);
        }

        // 再计算折扣
        double zhekouQuota = (double) zheKou.getTemplate().getRule().getDiscount().getQuota();  // 折扣
        targetSum = targetSum * (zhekouQuota / 100f);
        ctInfos.add(zheKou);

        targetSum = targetSum>minCost() ? targetSum : minCost();

        settlement.setCost(retain2Decimals(targetSum));
        settlement.setCouponAndTemplateInfos(ctInfos);
        log.debug("Use ManJian And ZheKou Coupon Make Goods Cost From {} To {}",
                goodsSum, settlement.getCost());

        return settlement;
    }

    /**
     * <h2>当前的两张优惠券是否可以共用</h2>
     * 即校验 TemplateRule 中的 weight 是否满足条件
     * 只需一个TemplateRule的weight包含另一个template的key就行
     * */
    private boolean isTemplateCanShared(SettlementInfo.CouponAndTemplateInfo manJian, SettlementInfo.CouponAndTemplateInfo zheKou) {
        String manjianKey = manJian.getTemplate().getKey() +
                String.format("%04d",manJian.getTemplate().getId());
        String zhekouKey = zheKou.getTemplate().getKey()
                + String.format("%04d", zheKou.getTemplate().getId());

        List<String> manJianSharedKeys = JSON.parseObject(manJian.getTemplate().getRule().getWeight(), List.class);
        List<String> zhekouSharedKeys = JSON.parseObject(zheKou.getTemplate().getRule().getWeight(), List.class);

        return manJianSharedKeys.contains(zhekouKey) || zhekouSharedKeys.contains(manjianKey);
    }
}
